package cn.openea.perpartner.payment.web.wallet.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.openea.perpartner.common.core.manager.AsyncManager;
import cn.openea.perpartner.common.core.text.Convert;
import cn.openea.perpartner.common.core.utils.Arith;
import cn.openea.perpartner.common.core.utils.spring.SpringUtils;
import cn.openea.perpartner.payment.web.points.dto.PointsDto;
import cn.openea.perpartner.payment.web.points.service.IPointsService;
import cn.openea.perpartner.payment.web.points.service.IRateCenterService;
import cn.openea.perpartner.payment.web.wallet.dto.WalletDto;
import cn.openea.perpartner.payment.web.wallet.entity.Bills;
import cn.openea.perpartner.payment.web.wallet.entity.Wallet;
import cn.openea.perpartner.payment.web.wallet.mapper.WalletMapper;
import cn.openea.perpartner.payment.web.wallet.service.IBillsService;
import cn.openea.perpartner.payment.web.wallet.service.IDialogService;
import cn.openea.perpartner.payment.web.wallet.service.IWalletService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author Weird077
 * @description TODO
 * @date 2022-03-14 11:26
 */
@Service
@Slf4j
public class WalletServiceImpl extends ServiceImpl<WalletMapper, Wallet> implements IWalletService {

    @Resource
    private IBillsService billsService;
    @Resource
    private IPointsService pointsService;
    @Resource
    private IRateCenterService rateCenterService;


    @Value("${meily.uri}")
    private String meilyUri;
    @Value("${meily.api.hasCashOutPath}")
    private String meilyCashOutPath;

    @Override
    public Wallet queryUserCoin(WalletDto dto) {
        LambdaQueryWrapper<Wallet> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Wallet::getUserid, dto.getUserId());
        return baseMapper.selectOne(wrapper);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean pointsToWallet(WalletDto dto) {
        PointsDto pointsDto = new PointsDto();
        pointsDto.setUserId(dto.getUserId());
        pointsDto.setPoints(dto.getPoints());
        if (StrUtil.isBlank(dto.getReason())){
            pointsDto.setReason("转入钱包");
        }
        pointsDto.setOrderId(dto.getOrderId());
        pointsDto.setSceneId(dto.getSceneId());
        boolean isSuccess = pointsService.sub(pointsDto);
        if (isSuccess) {
            double rate = rateCenterService.getRate("wallet");
            double money = Arith.mul(Double.parseDouble(dto.getPoints()), rate);
            dto.setCoin(Convert.toStr(money));
            isSuccess = this.add(dto);
        }
        return isSuccess;
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean cashOut(WalletDto dto) {
        dto.setReason("提现");
        return sub(dto);
    }
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean deductBalance(WalletDto dto) {

        return sub(dto);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean recharge(WalletDto dto) {
        if (StrUtil.isBlank(dto.getReason())){
            dto.setReason("充值");
        }
        return add(dto);
    }

    @Override
    public List<Wallet> queryWalletList() {
        LambdaQueryWrapper<Wallet> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(Wallet::getCoin);
        return list(wrapper);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public boolean add(WalletDto dto) {
        LambdaQueryWrapper<Wallet> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Wallet::getUserid, dto.getUserId());
        Wallet wallet = getOne(wrapper);
        if (BeanUtil.isEmpty(wallet)) {
            wallet = new Wallet();
            wallet.setCoin("0.00");
            wallet.setUserid(dto.getUserId());
        }
        double cash = Double.parseDouble(wallet.getCoin());
        cash = Arith.add(cash, Double.parseDouble(dto.getCoin()));
        wallet.setCoin(String.valueOf(cash));
        dto.setOperType("add");
        // 异步记录钱包变动
        AsyncManager.me().execute(SpringUtils.getBean(IDialogService.class).recordDialog(dto.getUserId()));
        return saveOrUpdate(wallet) && billsService.insert(dto);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean sub(WalletDto dto) {
        LambdaQueryWrapper<Wallet> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Wallet::getUserid, dto.getUserId());
        Wallet wallet = getOne(wrapper);
        double cash = Double.parseDouble(wallet.getCoin());
        double coinOut = Double.parseDouble(dto.getCoin());
        if (coinOut > cash || coinOut <= 0) {
            return false;
        }
        cash = Arith.sub(cash, Double.parseDouble(dto.getCoin()));
        wallet.setCoin(String.valueOf(cash));
        dto.setOperType("sub");
        return update(wallet, wrapper) && billsService.insert(dto);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean walletToPoint(WalletDto dto) {
        dto.setReason("充值积分");
        boolean isSuccess = this.sub(dto);
        if (isSuccess) {
            double rate = rateCenterService.getRate("wallet");
            double points = Arith.div(Convert.toDouble(dto.getCoin()), rate);
            PointsDto pointsDto = new PointsDto();
            pointsDto.setUserId(dto.getUserId());
            pointsDto.setPoints(Convert.toStr(points));
            pointsDto.setReason(dto.getReason());
            pointsDto.setOrderId(dto.getOrderId());
            isSuccess = pointsService.add(pointsDto);
        }
        return isSuccess;
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean walletToPoints(WalletDto dto) {
        double rate = rateCenterService.getRate("wallet");
        double money = Arith.mul(Convert.toDouble(dto.getPoints()), rate);
        dto.setCoin(Convert.toStr(money));
        dto.setReason("充值积分");
        boolean isSuccess = this.sub(dto);
        if (isSuccess) {
            PointsDto pointsDto = new PointsDto();
            pointsDto.setUserId(dto.getUserId());
            pointsDto.setPoints(dto.getPoints());
            pointsDto.setReason(dto.getReason());
            pointsDto.setOrderId(dto.getOrderId());
            isSuccess = pointsService.add(pointsDto);
        }
        return isSuccess;
    }
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean repair(WalletDto dto) {
        Bills bills = billsService.getById(dto.getUnid());
        if (BeanUtil.isEmpty(bills)) {
            return false;
        }
        if (!bills.getUserid().equals(dto.getUserId())) {
            return false;
        }
        if(!bills.getCoin().equals(dto.getCoin())){
            return false;
        }
        dto.setUnid(IdUtil.simpleUUID());
        return  this.add(dto);
    }

    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    @Override
    public boolean emptyWallet(String userId) {
        LambdaUpdateWrapper<Wallet> wrapper = Wrappers.<Wallet>lambdaUpdate()
                .set(Wallet::getCoin, "0.00")
                .eq(Wallet::getUserid, userId);
        if (update(wrapper)) {
            return billsService.save(Bills.builder()
                    .reason("清空钱包")
                    .coin("0.00")
                    .opertype("sub")
                    .userid(userId)
                    .build());
        }
        return false;
    }

    @Override
    public boolean hasCashOut(String userId) {
        String url = meilyUri.concat(meilyCashOutPath).concat("/").concat(userId);
        String result = HttpRequest.get(url)
                .header("sysid","SysAdmin")
                .header("syspwd","pass")
                .execute().body();
        JSONObject obj = JSON.parseObject(result);
        return  Convert.toBool(obj.get("data"));
    }
}
